"""
Provides builders for use in the SCons scripts
"""
import SCons
from SCons.Builder import Builder

import sys
import os.path

def PyExtModule( env, target, source, **extras):
    '''
    Generate a python extension module
    '''
    libs = [env.subst('$BOOST_PYTHON_LIB_NAME')]
    try:
        libs = libs + extras['LIBS']
        del extras['LIBS']
    except KeyError:
        pass

    # firsrly, we use the standard SharedLibrary builder
    PDB = target + '.pdb',
    ret = env.SharedLibrary( target, source,  LIBS=[libs], PDB = PDB, **extras )

    # we look for the actual shared library
    # as opposed to any extra outputs
    def is_shared_lib(item):
        item = str(item)
        if not item.startswith(env.subst('$SHLIBPREFIX')):
            return False
        if not item.endswith(env.subst('$SHLIBSUFFIX')):
            return False
        return True
    shared_object = filter(is_shared_lib, ret)

    # we determine the correct name for the file
    proper_name = env.subst('$PYDLIBPREFIX') + target + env.subst('$PYDLIBSUFFIX')

    # and copy it there...
    # should we include all the rest of the items produced by
    # SharedLibrary above?
    inst = env.InstallAs(proper_name, shared_object)
    return inst

def wrapper_emitter( target, source, env):
    env.Depends( target, 'install_for_tests')
    return (target, source)

GenerateWrapper = Builder(
    action = sys.executable + ' ${MAKEWRAPPER} '
    '''${' '.join([ '-I "'+str(p)+'"' for p in PYXXPATH ])} '''+
    ' -M ${MODULE} ' +
    '"${SOURCE}" > "${TARGET}"',
    single_source = True,
    emitter = wrapper_emitter,
    src_suffix = '.pyx',
    suffix = '.cpp',
    )

def make_test(env, path, name, args):
    #wrappers, sources, headers, tests):
    env = env.Clone()
    env.Append(**args)

    headers = grab_files(env, 'h', path)

    pyxx_path = env.get('PYXXPATH', [])
    for header in headers:
        folder = os.path.dirname( str(header) )
        if folder not in pyxx_path:
            pyxx_path.append(folder)

    wrappers = grab_files(env, 'pyx', path)
    wrapper_sources = []
    for wrapper in wrappers:
        source = env.GenerateWrapper(wrapper, MODULE = name, PYXXPATH = pyxx_path)
        for header in headers:
            env.Depends(source, header)
        for wrapper in wrappers:
            env.Depends(source, wrapper)

    sources = grab_files(env, 'cpp', path)
    library = env.PyExtModule(
        name, 
        sources, 
        CPPPATH = [path, '#/include'] + env['CPPPATH'],
        LIBS = env.get('LIBS',[]))
    env.Depends(library, wrapper_sources)
    lib_inst = env.Install( env.subst('#/$CXX-$VARIANT/lib'), library)

    tests = grab_files(env, 'py', path)
    test_results = []
    for test in tests:
        run_test = env.Command( str(test) + ".out", test, sys.executable + " $SOURCE")
        env.Depends(run_test, lib_inst)
        test_results.append( run_test )
    return test_results

def relative_path(inpath):
    """
    return a path relative to the current directory
    """
    here = os.path.abspath('.')
    there = os.path.abspath(str(inpath))
    here = here.split(os.sep)
    there = there.split(os.sep)
    while here and there and here[0] == there[0]:
        here.pop(0)
        there.pop(0)

    path = ['..'] * len(here) + there
    return os.path.join(*path)

def grab_files(env, ext, path):
    files = env.Glob('%s/*.%s' % (path, ext))
    return files
    def test(file):
        if str(file) == os.path.abspath(str(file)):
            return True
        return False
    files = filter(test, files)
    print ext, path 
    print "\n".join( map(str, files) )
    return files

def install(env):
    env.AddMethod(PyExtModule, 'PyExtModule')
    env.AddMethod(make_test, 'RunTests')
    env.Append( 
        BUILDERS = {
            'GenerateWrapper' : GenerateWrapper
        },
    #    CPPPATH = [get_python_inc()]
    )


